<script>
import { optionsMerger, propsBinder, findRealParent, debounce } from "../../utils";
import Layer from "../../mixins/Layer";
import Options from "../../mixins/Options";
import { marker, DomEvent, Icon, latLng } from "leaflet";

/**
 * Marker component, lets you add and personalize markers on the map
 */
export default {
    name: "LMarker",
    mixins: [Layer, Options],
    props: {
        pane: {
            type: String,
            default: "markerPane",
        },
        draggable: {
            type: Boolean,
            custom: true,
            default: false,
        },
        latLng: {
            type: [Object, Array],
            custom: true,
            default: null,
        },
        icon: {
            type: [Object],
            custom: false,
            default: () => new Icon.Default(),
        },
        opacity: {
            type: Number,
            custom: false,
            default: 1.0,
        },
        zIndexOffset: {
            type: Number,
            custom: false,
            default: null,
        },
    },
    data() {
        return {
            ready: false,
        };
    },
    beforeDestroy() {
        if (this.debouncedLatLngSync) {
            this.debouncedLatLngSync.cancel();
        }
    },
    mounted() {
        const options = optionsMerger(
            {
                ...this.layerOptions,
                icon: this.icon,
                zIndexOffset: this.zIndexOffset,
                draggable: this.draggable,
                opacity: this.opacity,
            },
            this
        );
        this.mapObject = marker(this.latLng, options);
        DomEvent.on(this.mapObject, this.$listeners);
        this.debouncedLatLngSync = debounce(this.latLngSync, 100);
        this.mapObject.on("move", this.debouncedLatLngSync);
        propsBinder(this, this.mapObject, this.$options.props);
        this.parentContainer = findRealParent(this.$parent);
        this.parentContainer.addLayer(this, !this.visible);
        this.ready = true;
        this.$nextTick(() => {
            /**
             * Triggers when the component is ready
             * @type {object}
             * @property {object} mapObject - reference to leaflet map object
             */
            this.$emit("ready", this.mapObject);
        });
    },
    methods: {
        setDraggable(newVal, oldVal) {
            if (this.mapObject.dragging) {
                newVal
                    ? this.mapObject.dragging.enable()
                    : this.mapObject.dragging.disable();
            }
        },
        setLatLng(newVal) {
            if (newVal == null) {
                return;
            }

            if (this.mapObject) {
                const oldLatLng = this.mapObject.getLatLng();
                const newLatLng = latLng(newVal);
                if (
                    newLatLng.lat !== oldLatLng.lat ||
                    newLatLng.lng !== oldLatLng.lng
                ) {
                    this.mapObject.setLatLng(newLatLng);
                }
            }
        },
        latLngSync(event) {
            this.$emit("update:latLng", event.latlng);
            this.$emit("update:lat-lng", event.latlng);
        },
    },
    render: function (h) {
        if (this.ready && this.$slots.default) {
            return h(
                "div",
                { style: { display: "none" } },
                this.$slots.default
            );
        }
        return null;
    },
};
</script>
